#!/usr/bin/env python
### -*- Mode: Python -*-
### Code from Paradigms of Artificial Intelligence Programming
### File gps1.py: First version of GPS (General Problem Solver)


State = [] #The current state: a list of conditions.
Ops = [] #A list of available operators.

class Op:
    """An operation"""
    def __init__(self, action, preconds, add_list, del_list):
        self.action = action
        self.preconds = preconds
        self.add_list = add_list
        self.del_list = del_list

def GPS(state, goals, ops):
    """General Problem Solver: achieve all goals using ops."""
    if all(map(achieve,goals)):
        print 'solved'
    else:
        print 'failed'

def achieve(goal):
    """A goal is achieved if it already holds, or if there is an appropriate op for it that is applicable."""
    return (goal in State) or (any (map(apply_op,find_all(goal, Ops, test=appropriate_p))))

def appropriate_p(goal, op):
    """An op is appropriate to a goal if it is in its add list."""
    return goal in op.add_list

def apply_op(op):
    """Print a message and update *state* if op is applicable."""
    if all(map(achieve,op.preconds)):
        print "Executing "+op.action
        for op_del in op.del_list:
            if op_del in State:
                State.remove(op_del)
        for op_add in op.add_list:
            if op_add not in State:
                State.append(op_add)
        return True 
    return False

def find_all(item, sequence, test):
    match_list = []
    for op in sequence:
        if test(item,op):
            match_list.append(op)
    return match_list


##################### Testing for the "drive son to school problem"
school_ops = []


drive_son_to_school = Op("drive-son-to-school", ["son-at-home", "car-works"], ["son-at-school"], ["son-at-home"])
school_ops.append(drive_son_to_school)

shop_installs_battery = Op("shop-installs-battery", ["car-needs-battery", "shop-knows-problem", "shop-has-money"], ["car-works"], [])
school_ops.append(shop_installs_battery)

tell_shop_problem = Op("tell-shop-problem", ["in-communication-with-shop"], ["shop-knows-problem"], [])
school_ops.append(tell_shop_problem)

telephone_shop = Op("telephone-shop", ["know-phone-number"], ["in-communication-with-shop"], [])
school_ops.append(telephone_shop)

look_up_number = Op("look-up-number", ["have-phone-book"], ["know-phone-number"], [])
school_ops.append(look_up_number)

give_shop_money = Op("give-shop-money", ["have-money"], ["shop-has-money"], ["have-money"])
school_ops.append(give_shop_money)

Ops = school_ops
State = ["son-at-home", "car-needs-battery", "have-money", "shop-knows-problem"]
Goals = ["son-at-school"]
GPS(State, Goals, Ops)
